package com.zjl.Zookeeper.第05章_分布式锁;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;
import org.springframework.expression.spel.ast.NullLiteral;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * TODO 是个错误的
 */
public class A_自造分布式锁 {
    private static ZooKeeper zooKeeper;
    public static final String lockPathMAIN = "/locks1";
    static {
        try {
            // ZooKeeper服务器地址和端口  connectString的值不能有空格
            //String connectString = "82.157.71.243:2181,82.157.71.243:2181,82.157.71.243:2181";
            String connectString = "82.157.71.243:2181"; // ZooKeeper服务器地址和端口
            int sessionTimeout = 2000; // 会话超时时间（毫秒）
            zooKeeper = new ZooKeeper(connectString, sessionTimeout, event -> {
                System.out.println("************************************************");
            });

            Stat exists = zooKeeper.exists(lockPathMAIN, false);
            if(exists == null){
                //没有根节点，创建根节点
                String s = zooKeeper.create(lockPathMAIN, "锁根节点".getBytes(),
                        ZooDefs.Ids.OPEN_ACL_UNSAFE,
                        CreateMode.PERSISTENT
                );
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
    public static final String lockPath = "/locks1";

    public static void main(String[] args) throws Exception {


        zkLock zkLock = new zkLock(zooKeeper,lockPathMAIN + "/x1");
        System.out.println("开始测试锁");
        for (int i = 0; i < 5; i++) {
            final int j = i;
            new Thread(()->{
                try {
                    String lock = zkLock.lock("/sq-");
                    System.out.println("获取锁" + j);
                    System.out.println("释放锁" + j);
                    zkLock.unlock(lock);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }).start();
        }


    }

}
class zkLock{

    static Map<String,CountDownLatch> locks = new ConcurrentHashMap<>();

    private CountDownLatch waitLatch=new CountDownLatch(1);//1次结束


    private String waitPath;//监听的锁
    private String lockPath;//监听的锁
    private ZooKeeper zooKeeper;//监听的锁
    public zkLock(ZooKeeper zooKeeper,String lockPath) throws Exception {
        Thread.currentThread().getName();
        this.zooKeeper = zooKeeper;
        this.lockPath = lockPath;
        Stat exists = zooKeeper.exists(lockPath,event -> {

            System.out.println("---释放了" + event.getPath());
            if(event.getType() == Watcher.Event.EventType.NodeDeleted
                    && event.getPath().equals(waitPath)){
//                waitLatch.countDown();
            }

        });
        if(exists == null){
            //没有根节点，创建根节点
            String s = zooKeeper.create(lockPath, "锁节点".getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT
            );
        }


    }


    //加锁
    public String lock(String lock) throws Exception {

        String lockPath001 = zooKeeper.create(lockPath + lock, null,
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("加锁：" + lockPath001);
        getLock(lock,lockPath001);
        return lockPath001;

    }

    private void getLock(String lock,String lockPath001) throws KeeperException, InterruptedException {
        //获取有哪些节点
        List<String> children = zooKeeper.getChildren(lockPath, false);

        if(children.size() == 1){
            System.out.println("只有我我一个节点");
            return;
        }else{
            Collections.sort(children);//排序
            //节点名字
            String thisNode = lockPath001.substring(lockPath.length() + 1);
            int i = children.indexOf(thisNode);//获得
            if(i == -1){
                System.out.println("不可能不存在");
            }else if(i == 0){//是第一个节点
                System.out.println("我是第一个节点");
                return;
            }else{
                waitPath = lockPath + "/" + children.get(i-1);
                zooKeeper.exists(waitPath,event->{
                    System.out.println("---释放了" + event.getPath());
                    if(event.getType() == Watcher.Event.EventType.NodeDeleted
                            && event.getPath().equals(waitPath)){
                        waitLatch.countDown();
                    }

                });
                System.out.println("排队" + waitPath);
                waitLatch.await();
                return;
            }

        }
    }

    //释放锁
    public void unlock(String lock) throws Exception {
        System.out.println("释放锁：" + lock);
        zooKeeper.delete(lock,-1);
    }
}
